package com.cyys.modules.system.service.serial;

import com.cyys.common.services.CyysBaseService;
import com.cyys.common.utils.date.DateUtil;
import com.cyys.modules.system.dao.serial.SerialNumberDao;
import com.cyys.modules.system.model.serial.SerialNumber;
import org.springframework.cache.annotation.CachePut;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.locks.ReentrantLock;

@Service("serialNumberService")
@Transactional(readOnly = true)
public class SerialNumberService extends CyysBaseService<SerialNumberDao, SerialNumber> {

	/** 格式 */
	private String pattern = "";

	/** 生成器锁 */
	private final ReentrantLock lock = new ReentrantLock();

	/** 流水号格式化器 */
	private DecimalFormat format = null;

	/** 预生成锁 */
	private final ReentrantLock prepareLock = new ReentrantLock();

	/** 最小值 */
	private int min = 0;

	/** 最大值 */
	private long max = 0;

	/** 已生成流水号（种子） */
	private long seed = min;

	/** 预生成数量 */
	private int prepare = 0;

	/** 数据库存储的当前最大序列号 **/
	long maxSerialInt = 0;

	/** 当前序列号是否为个位数自增的模式 **/
	private String isAutoIncrement = "0";

	SerialNumber systemSerialNumber = new SerialNumber();

	/** 预生成流水号 */
	HashMap<String, List<String>> prepareSerialNumberMap = new HashMap<>();

	@Transactional(readOnly = false)
	public int getNextSerialNumber(String moudelCode) throws Exception{
		SerialNumber serialNumber = dao.getByModuleCode(moudelCode, 0);
		if(serialNumber != null){
			int maxSerial = Integer.valueOf(serialNumber.getMaxSerial());
			int maxSerialNext = maxSerial + 1;
			serialNumber.setMaxSerial(maxSerialNext + "");
			dao.updateById(serialNumber);
			return Integer.valueOf(maxSerial);
		}
		return -1;
	}

	/**
	 * 根据模块code生成预数量的序列号存放到Map中
	 * @param moduleCode 模块code
	 * @return
	 */
	@Transactional(readOnly = false)
	@CachePut(value = "serialNumber",key="#moduleCode")
	public List<String> generatePrepareSerialNumbers(String moduleCode) throws Exception{
		//临时List变量
		List<String> resultList = new ArrayList<String>(prepare);
		lock.lock();
		try{
			for(int i=0;i<prepare;i++){
				maxSerialInt  = maxSerialInt + 1;
				if(maxSerialInt > min && (maxSerialInt + "").length() < max ){
					seed = maxSerialInt ;
				}else{
					//如果动态数字长度大于模板中的长度 例：模板CF000  maxSerialInt 1000
					seed = maxSerialInt = 0;
					//更新数据，重置maxSerialInt为0
					systemSerialNumber.setMaxSerial("0");
					dao.insert(systemSerialNumber);
				}
				//动态数字生成
				String formatSerialNum = format.format(seed);
				//动态日期的生成
				if(pattern.contains("${DATE}")){
					String currentDate = DateUtil.format(new Date(),"yyyyMMdd");
					formatSerialNum = formatSerialNum.replace("${DATE}",currentDate);
				}

				resultList.add(formatSerialNum);
			}
			//更新数据
			systemSerialNumber.setMaxSerial(maxSerialInt + "");
			dao.insert(systemSerialNumber);
		}finally{
			lock.unlock();
		}
		return resultList;
	}

	/**
	 * 根据模块code生成序列号
	 * @param moduleCode  模块code
	 * @return  序列号
	 */
	@Transactional(readOnly = false)
	public String generateSerialNumberByModelCode(String moduleCode) throws Exception{
		//预序列号加锁
		prepareLock.lock();
		try{
			//判断内存中是否还有序列号
			if(null != prepareSerialNumberMap.get(moduleCode) && prepareSerialNumberMap.get(moduleCode).size() > 0){
				//若有，返回第一个，并删除
				return prepareSerialNumberMap.get(moduleCode).remove(0);
			}
		}finally {
			//预序列号解锁
			prepareLock.unlock();
		}
		systemSerialNumber = dao.getByModuleCode(moduleCode, 0);
		prepare = Integer.parseInt(systemSerialNumber.getPreMaxNum().trim());//预生成流水号数量
		pattern = systemSerialNumber.getConfigTemplet().trim();//配置模板
		String maxSerial = systemSerialNumber.getMaxSerial().trim(); //存储当前最大值
		isAutoIncrement = systemSerialNumber.getIsAutoIncrement().trim();
		maxSerialInt = Long.parseLong(maxSerial.trim());//数据库存储的最大序列号
		max = this.counter(pattern,'0') + 1;//根据模板判断当前序列号数字的最大值
		if(isAutoIncrement.equals("1")){
			pattern = pattern.replace("0","#");
		}
		format = new DecimalFormat(pattern);
		//生成预序列号，存到缓存中
		List<String> resultList = generatePrepareSerialNumbers(moduleCode);
		prepareLock.lock();
		try {
			prepareSerialNumberMap.put(moduleCode, resultList);
			return prepareSerialNumberMap.get(moduleCode).remove(0);
		} finally {
			prepareLock.unlock();
		}
	}

	/**
	 * 设置最小值
	 *
	 * @param value 最小值，要求：大于等于零
	 * @return 流水号生成器实例
	 */
	public SerialNumberService setMin(int value) {
		lock.lock();
		try {
			this.min = value;
		}finally {
			lock.unlock();
		}
		return this;
	}

	/**
	 * 最大值
	 *
	 * @param value 最大值，要求：小于等于Long.MAX_VALUE ( 9223372036854775807 )
	 * @return 流水号生成器实例
	 */
	public SerialNumberService setMax(long value) {
		lock.lock();
		try {
			this.max = value;
		}finally {
			lock.unlock();
		}
		return this;
	}

	/**
	 * 设置预生成流水号数量
	 * @param count 预生成数量
	 * @return      流水号生成器实例
	 */
	public SerialNumberService setPrepare(int count) {
		lock.lock();
		try {
			this.prepare = count;
		}finally {
			lock.unlock();
		}
		return this;
	}

	/**
	 * 统计某一个字符出现的次数
	 * @param str 查找的字符
	 * @param c
	 * @return
	 */
	private int counter(String str,char c){
		int count=0;
		for(int i = 0;i < str.length();i++){
			if(str.charAt(i)==c){
				count++;
			}
		}
		return count;
	}

}
